package com.ruoyi.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.dto.SyTraditionalReservationDTO;
import com.ruoyi.system.enumeration.SySelfServiceBookingOrderLogEnum;
import com.ruoyi.system.enumeration.SyTraditionalReservationEnum;
import com.ruoyi.system.mapper.SyTraditionalReservationMapper;
import com.ruoyi.system.service.*;
import com.ruoyi.system.util.AbdulEmptyUtils;
import com.ruoyi.system.util.BookingNumberGenerator;
import com.ruoyi.system.util.StoreIdUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class SyTraditionalReservationServiceImpl extends ServiceImpl<SyTraditionalReservationMapper, SyTraditionalReservation> implements SyTraditionalReservationService {

    @Autowired
    private ISyBillLadingDetailsService billLadingDetailsService;

    @Autowired
    private ITableCategoriesService tableCategoriesService;

    @Autowired
    private ITableInfoService infoService;

    @Autowired
    private StoreIdUtils storeIdUtils;

    @Autowired
    private SySelfServiceBookingOrderLogService logService;


    private static final int TIME_WINDOW_HOURS = 4; //预约时间的前后四小时是否有人预约

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(SyTraditionalReservationDTO reservationDTO) {
        //预约的时候需要判断预抵时间的前后四个小时 是否有人预约  有则失败  预约的门店
        Date sstimatedArrivalTime = reservationDTO.getSstimatedArrivalTime();
        Date startTime = DateUtils.addHours(sstimatedArrivalTime, -TIME_WINDOW_HOURS); // 前4小时
        Date endTime = DateUtils.addHours(sstimatedArrivalTime, TIME_WINDOW_HOURS);   // 后4小时
        LambdaQueryWrapper<SyTraditionalReservation> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(SyTraditionalReservation::getTableClassification, reservationDTO.getDeskClassification());
        wrapper.eq(SyTraditionalReservation::getBookingDesk, reservationDTO.getBookingDesk());
        wrapper.between(SyTraditionalReservation::getSstimatedArrivalTime, startTime, endTime);
        wrapper.ne(SyTraditionalReservation::getStatus, SyTraditionalReservationEnum.STATUS_WAIT_CONFIRM.getKey());
        //获取门店id
        Long storeId = storeIdUtils.getStoreId();
        wrapper.eq(SyTraditionalReservation::getStoreId, storeId);
        List<SyTraditionalReservation> list = this.list(wrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            throw new RuntimeException("该时间段已有人预约，请重新选择时间");
        }
        //生成随机编号
        String number = BookingNumberGenerator.generateBookingNumber();
        SyTraditionalReservation reservation = new SyTraditionalReservation();
        reservation.setDetailNumber(number);
        reservation.setBookingPerson(reservationDTO.getBookingPerson());
        reservation.setBookingPhone(reservationDTO.getBookingPhone());
        reservation.setBookingDesk(reservationDTO.getBookingDesk());
        reservation.setSstimatedArrivalTime(reservationDTO.getSstimatedArrivalTime());
        reservation.setAutomaticallyCancelTime(reservationDTO.getAutomaticallyCancelTime());
        reservation.setBookingStaff(reservationDTO.getBookingStaff());
        reservation.setStatus(SyTraditionalReservationEnum.STATUS_WAIT_RESERVATION.getKey());
        reservation.setRemark(reservationDTO.getBookingRemark());
        reservation.setTableClassification(reservationDTO.getDeskClassification());
        reservation.setCreateTime(new Date());
        reservation.setUpdateTime(new Date());
        reservation.setCreateBy(SecurityUtils.getUsername());
        reservation.setUpdateBy(SecurityUtils.getUsername());
        reservation.setStoreId(storeId);
        if (reservationDTO.getIsSendBookingSms() == 1) {
            //TODO 如果要发送短信的话那么这里写他的业务逻辑

        }
        reservation.setBookingOrderNumber(BookingNumberGenerator.generateBookingNumber());
        return this.save(reservation);
    }


    @Override
    public IPage<SyTraditionalReservation> list(SyTraditionalReservation reservation) {
        LambdaQueryWrapper<SyTraditionalReservation> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(StringUtils.isNotEmpty(reservation.getBookingStaff()), SyTraditionalReservation::getBookingStaff, reservation.getBookingStaff());
        wrapper.eq(StringUtils.isNotEmpty(reservation.getBookingPerson()), SyTraditionalReservation::getBookingPerson, reservation.getBookingPerson());
        wrapper.eq(StringUtils.isNotEmpty(reservation.getBookingDesk()), SyTraditionalReservation::getBookingDesk, reservation.getBookingDesk());
        wrapper.eq(StringUtils.isNotEmpty(reservation.getTableClassification()), SyTraditionalReservation::getTableClassification, reservation.getTableClassification());
        wrapper.eq(reservation.getStatus() != null, SyTraditionalReservation::getStatus, reservation.getStatus());
        Long storeId = storeIdUtils.getStoreId();
        wrapper.eq(SyTraditionalReservation::getStoreId, storeId);
        if (reservation.getStartTime() != null && reservation.getEndTime() != null) {
            wrapper.between(SyTraditionalReservation::getSstimatedArrivalTime, reservation.getStartTime(), reservation.getEndTime());
        }
        wrapper.orderByDesc(SyTraditionalReservation::getUpdateTime);
        IPage<SyTraditionalReservation> page = new Page<>(reservation.getPageNum(), reservation.getPageSize());
        IPage<SyTraditionalReservation> list = this.page(page, wrapper);
//        List<SyTraditionalReservation> list = this.list(wrapper);
        if (CollectionUtils.isNotEmpty(list.getRecords())) {
            list.getRecords().forEach(e -> {
                Integer status = e.getStatus();
                e.setStatusDesc(SyTraditionalReservationEnum.getValueByKey(status));

            });
        }
        return list;
    }

    @Override
    public Boolean update(SyTraditionalReservation reservation) {

        if (AbdulEmptyUtils.isEmpty(reservation)) {
            return false;
        }
        SyTraditionalReservation byId = this.getById(reservation.getId());
        if (AbdulEmptyUtils.isEmpty(byId)) {
            return false;
        }
        if (!byId.getStatus().equals(SyTraditionalReservationEnum.STATUS_WAIT_RESERVATION.getKey())) {
            throw new RuntimeException("该订单已处理，请勿重复处理");
        }

        if (reservation.getOperationType().equals(1)) {
            //修改
            if (AbdulEmptyUtils.isEmpty(reservation.getSstimatedArrivalTime())) {
                throw new RuntimeException("预抵时间不能为空");
            }
            List<SyTraditionalReservation> check = check(reservation.getSstimatedArrivalTime(), byId.getTableClassification(), byId.getBookingDesk());
            if (!AbdulEmptyUtils.isEmpty(check)) {
                throw new RuntimeException("该时间段已有人预约，请重新选择时间");
            }
            addLog(byId.getBookingPhone(), byId.getBookingDesk(), byId.getBookingOrderNumber(),byId.getTableClassification(), SySelfServiceBookingOrderLogEnum.MODIFY_TIME.getCode(),byId.getBookingPhone());
        } else if (reservation.getOperationType().equals(2)) {
            //转台
            if (AbdulEmptyUtils.isEmpty(reservation.getTableClassification()) || AbdulEmptyUtils.isEmpty(reservation.getBookingDesk())) {
                throw new RuntimeException("桌台分类和桌台不能为空");
            }
            List<SyTraditionalReservation> check = check(byId.getSstimatedArrivalTime(), reservation.getTableClassification(), reservation.getBookingDesk());

            if (!AbdulEmptyUtils.isEmpty(check)) {
                throw new RuntimeException("转台失败，此台该时段已被预约");
            }
            //增加转台操作日志
            addLog(byId.getBookingPhone(), reservation.getBookingDesk(), byId.getBookingOrderNumber(),reservation.getTableClassification(), SySelfServiceBookingOrderLogEnum.TRANSFER.getCode(),byId.getBookingPhone());
        }

        if (!AbdulEmptyUtils.isEmpty(reservation.getBookingPerson())) {
            byId.setBookingPerson(reservation.getBookingPerson());
        }
        if (!AbdulEmptyUtils.isEmpty(reservation.getBookingPhone())) {
            byId.setBookingPhone(reservation.getBookingPhone());
        }
        if (!AbdulEmptyUtils.isEmpty(reservation.getBookingDesk())) {
            byId.setBookingDesk(reservation.getBookingDesk());
        }
        if (!AbdulEmptyUtils.isEmpty(reservation.getSstimatedArrivalTime())) {
            byId.setSstimatedArrivalTime(reservation.getSstimatedArrivalTime());
        }
        if (!AbdulEmptyUtils.isEmpty(reservation.getAutomaticallyCancelTime())) {
            byId.setAutomaticallyCancelTime(reservation.getAutomaticallyCancelTime());
        }
        if (!AbdulEmptyUtils.isEmpty(reservation.getBookingStaff())) {
            byId.setBookingStaff(reservation.getBookingStaff());
        }
        if (!AbdulEmptyUtils.isEmpty(reservation.getStatus())) {
            byId.setStatus(reservation.getStatus());
            byId.setAutomaticallyCancelTime(new Date());
        }
        if (!AbdulEmptyUtils.isEmpty(reservation.getBookingRemark())) {
            byId.setRemark(reservation.getBookingRemark());
        }
        if (!AbdulEmptyUtils.isEmpty(reservation.getTableClassification())) {
            byId.setTableClassification(reservation.getTableClassification());
        }
        byId.setUpdateTime(new Date());
        return this.updateById(byId);
    }

    /**
     * 增加操作日志
     * 电话、桌台、订单号、桌台分类、操作类型 ,预定人
     */
    private void addLog(String BookingPhone, String BookingDesk,String BookingOrderNumber,String TableClassification,Integer type,String BookingPerson) {
        SySelfServiceBookingOrderLog log = new SySelfServiceBookingOrderLog();
        log.setPhone(BookingPhone);
        log.setDesk(BookingDesk);
        log.setBookingNumber(BookingOrderNumber);
        log.setTableClassification(TableClassification);
        log.setType(type);
        log.setVipMessage(BookingPerson);
        logService.add(log);
    }

    /**
     * 转台 修改 操作逻辑
     */
    public List<SyTraditionalReservation> check(Date arrivalTime, String deskClassification, String deskId) {
        LambdaQueryWrapper<SyTraditionalReservation> wrapper = Wrappers.lambdaQuery();
        Date startTime = DateUtils.addHours(arrivalTime, -TIME_WINDOW_HOURS); // 前4小时
        Date endTime = DateUtils.addHours(arrivalTime, TIME_WINDOW_HOURS);   // 后4小时
        wrapper.eq(SyTraditionalReservation::getTableClassification, deskClassification);
        wrapper.eq(SyTraditionalReservation::getBookingDesk, deskId);
        wrapper.between(SyTraditionalReservation::getSstimatedArrivalTime, startTime, endTime);
        wrapper.eq(SyTraditionalReservation::getStatus, SyTraditionalReservationEnum.STATUS_WAIT_RESERVATION.getKey());
        //获取门店id
        Long storeId = storeIdUtils.getStoreId();
        wrapper.eq(SyTraditionalReservation::getStoreId, storeId);
        return this.list(wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean openOrder(SyBillLadingDetails ladingDetails) {
        if (AbdulEmptyUtils.isEmpty(ladingDetails.getOpeningTime()) || AbdulEmptyUtils.isEmpty(ladingDetails.getTaiwanFeeRules())) {
            throw new RuntimeException("开单时间或台费规则不能为空");
        }
        //开单 首先需要判断当前桌台是否正在使用  其次需要当前订单为已预约 更新订单状态为已开单  同时更新桌台信息表为正在使用 并且生成一条订单明细表记录
        LambdaQueryWrapper<TableCategories> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(TableCategories::getCategoryName, ladingDetails.getDeskClassification());
        wrapper.last("limit 1");
        TableCategories categoriesServiceOne = tableCategoriesService.getOne(wrapper);
        if (AbdulEmptyUtils.isEmpty(categoriesServiceOne)) {
            throw new RuntimeException("当前桌台不存在");
        }
        LambdaQueryWrapper<TableInfo> query = Wrappers.lambdaQuery();
        query.eq(TableInfo::getTableCategoryId, categoriesServiceOne.getId());
        query.eq(TableInfo::getTableName, ladingDetails.getDesk());
        query.eq(TableInfo::getIsStatus, 1);
        query.last("limit 1");

        TableInfo infoServiceOne = infoService.getOne(query);
        if (AbdulEmptyUtils.isEmpty(infoServiceOne)) {
            throw new RuntimeException("当前桌台不存在");
        }
        if (infoServiceOne.getIsUsage().equals(1)) {
            throw new RuntimeException("开台失败，当前桌台正在使用");
        }
        ladingDetails.setStoreId(storeIdUtils.getStoreId());
        if (ladingDetails.getOpeningMethod().equals(1)) {
            //直接开单
            //生成订单明细记录
            return billLadingDetailsService.save(ladingDetails);
        } else {
            //预订开单
            if (AbdulEmptyUtils.isEmpty(ladingDetails.getTraditionalReservationdetailNumber())) {
                throw new RuntimeException("请选择传统预订开台明细编号");
            }
            LambdaQueryWrapper<SyTraditionalReservation> lambdaQuery = Wrappers.lambdaQuery();
            lambdaQuery.eq(SyTraditionalReservation::getDetailNumber, ladingDetails.getTraditionalReservationdetailNumber());
            SyTraditionalReservation reservation = this.getOne(lambdaQuery);
            if (AbdulEmptyUtils.isEmpty(reservation)) {
                throw new RuntimeException("当前传统预订订单不存在");
            }
            //更新订单状态为已开单
            reservation.setStatus(SyTraditionalReservationEnum.STATUS_WAIT_ORDER.getKey());
            reservation.setUpdateTime(new Date());
            this.updateById(reservation);
            //更新桌台信息表为正在使用
            infoServiceOne.setIsUsage(1);
            infoService.updateById(infoServiceOne);
            //生成订单明细记录
            ladingDetails.setCreateBy(SecurityUtils.getUsername());
            ladingDetails.setCreateTime(new Date());
            ladingDetails.setUpdateBy(SecurityUtils.getUsername());
            ladingDetails.setUpdateTime(new Date());
            return billLadingDetailsService.save(ladingDetails);
        }
    }
}
